package justweb

import (
	"fmt"
	"regexp"
	"strings"
)

// 与结点相关的创建方法 -- 这个是一种设计模式
// 这份代码比重构之前更加简洁易扩展

// 默认的匹配规则——支持通配符、:param、正则
// 输入符号，判定数据哪种node
func default_newNode(path string) BaseNode {
	if path == "*" {
		return newAnyNode()
	}
	if strings.HasPrefix(path, ":") && !strings.Contains(path, ":reg") {
		return newParamNode(path)
	}
	if strings.HasPrefix(path, ":") && strings.Contains(path, ":reg") {
		return newRegNode(path)
	}
	return newStaticNode(path)
}

// 创建根结点
func newRootNode(path string) *treenode {
	return &treenode{
		ChildNodes: make([]*treenode, 0, 2),
		matchChild: func(path string, c *Context) bool {
			panic("never call me")
		},
		nodeType: nodeTypeRoot,
		// path:     path,
	}
}

// 静态结点
func newStaticNode(path string) *treenode {
	return &treenode{
		ChildNodes: make([]*treenode, 0, 2),
		matchChild: func(p string, c *Context) bool {
			return p == path && p != "*"
		},
		nodeType: nodeTypeStatic,
		path:     path,
	}
}

// 通配符结点
func newAnyNode() *treenode {
	return &treenode{
		// ChildNodes: make([]*treenode, 0 ,1), // 由于通配符匹配不支持*/xx，所以这个可以省略
		matchChild: func(path string, c *Context) bool {
			return true // 表示都匹配
		},
		nodeType: nodeTypeAny,
		path:     "*",
	}
}

// 路径参数结点 - 和通配符一样来者不拒，但是需要记录与判断
func newParamNode(path string) *treenode {
	return &treenode{
		ChildNodes: make([]*treenode, 0, 2),
		matchChild: func(p string, c *Context) bool {
			if c != nil {
				c.PathParams[path[1:]] = p
			}
			// 如果自身是一个参数路由
			// 然后突然又在这个地方注册一个通配*  就是位置重叠了，命中谁的问题
			return p != "*" // 表示不认*
		},
		nodeType: nodeTypeParam,
		path:     path,
	}

}

// :reg([1,9]+)
// 正则节点 -- 其实效率并不高
func newRegNode(path string) *treenode {
	// 依据你的规则拿到正则表达式
	// idx := strings.Index(path, "(")
	s := strings.Split(path, ":reg")
	if len(s) <= 0 {
		return newStaticNode(path)
	}
	return &treenode{
		ChildNodes: make([]*treenode, 0, 2),
		matchChild: func(p string, c *Context) bool {
			// 针对正则的匹配的
			t, err := regexp.MatchString(s[1], p)
			if nil != err {
				fmt.Println("正则表达式解析失败: ", err)
			}
			return t
		},
		nodeType: nodeTypeReg,
		path:     path,
	}
}
